#ifndef STRING_UTIL_H
#define STRING_UTIL_H

#include <string>
#include <memory>
#include <vector>

namespace base
{
namespace utils
{
/**
 * @brief:  是否区分大小写
 */
enum CaseSensitivity
{
    CaseInsensitive = 0,//不区分大小写
    CaseSensitive       //区分大小写
};

/**
 * @brief:  分割字符串的行为定义
 */
enum SplitBehavior
{
    KeepEmptyParts = 0, //如果字段是空的，也放在结果里
    SkipEmptyParts      //如果字段是空的，不放在结果里
};
/**
 * 常用字符串工具，基于std::string，用于ASCII字符串处理，对std::string的补充
 *
 * @author: haitao.lin
 */
class StringUtil
{
public:

    StringUtil();

    /**
     * @brief:  判断str是否是标识符，即数字、字母和下划线
     * @author: sherlock_lht
     */
    static bool isIdentifier(const std::string &str);

    /**
     * @brief:  判断str是否是数字
     * @author: sherlock_lht
     */
    static bool isDigit(const std::string &str);

    /**
     * Supports C-style string formatting
     * used with caution in the loop
     */
    template<typename ... Args>
    static std::string format(const char *format, Args ... args)
    {
        auto size_buf = std::snprintf(nullptr, 0, format, args ...) + 1;
        std::unique_ptr<char[]> buf(new(std::nothrow) char[size_buf]);

        if (!buf)
            return std::string("");

        std::snprintf(buf.get(), size_buf, format, args ...);
        return std::string(buf.get(), buf.get() + size_buf - 1);
    }

    /**
     * Returns a lowercase copy of the string.
     */
    static std::string toLower(const std::string &origin_str);

    /**
     * Returns an uppercase copy of the string.
     */
    static std::string toUpper(const std::string &origin_str);

    /**
     * Returns true if the string starts with s; otherwise returns false.
     * If cs is sh::CaseSensitive (default), the search is case sensitive;
     * otherwise the search is case insensitive.
     */
    static bool startsWith(const std::string &origin_str, const std::string &substr,
                           CaseSensitivity cs = CaseSensitivity::CaseSensitive);

    /**
     * Returns true if the string ends with s; otherwise returns false.
     * If cs is sh::CaseSensitive (default), the search is case sensitive;
     * otherwise the search is case insensitive.
     */
    static bool endsWith(const std::string &origin_str, const std::string &substr,
                         CaseSensitivity cs = CaseSensitivity::CaseSensitive);

    /**
     * Compares s1 with s2 and returns an integer less than, equal to,
     * or greater than zero if s1 is less than, equal to, or greater than s2.
     *
     * If cs is sh::CaseSensitive, the comparison is case sensitive; otherwise the comparison is case insensitive.
     */
    static int compare(const std::string &s1, const std::string &s2,
                       CaseSensitivity cs = CaseSensitivity::CaseSensitive);

    /**
     * Returns true if this string contains an occurrence of the string str;
     * otherwise returns false.
     *
     * If cs is sh::CaseSensitive (default), the search is case sensitive;
     * otherwise the search is case insensitive.
     */
    static bool contains(const std::string &str, const std::string &substr,
                         CaseSensitivity cs = CaseSensitivity::CaseSensitive);

    /**
     * Splits the string into substrings wherever sep occurs, and returns the list of those strings.
     * If sep does not match anywhere in the string, split() returns a single-element list containing this string.
     * cs specifies whether sep should be matched case sensitively or case insensitively.
     * If behavior is sh::SkipEmptyParts, empty entries don't appear in the result.
     * By default, empty entries are kept.
     */
    static std::vector<std::string> split(const std::string &str, const std::string &sep,
                                          SplitBehavior behavior = SplitBehavior::KeepEmptyParts,
                                          CaseSensitivity cs = CaseSensitivity::CaseSensitive);

    /**
     * Returns a string that has token removed from the start.
     */
    static std::string trimLeft(const std::string &str, const std::string &token = " ");

    /**
     * Returns a string that has token removed from the end.
     */
    static std::string trimRight(const std::string &str, const std::string &token = " ");

    /**
     * Returns a string that has token removed from the start and end.
     */
    static std::string trim(const std::string &str, const std::string &token = " ");

    /**
     * Returns a string that has whitespace removed from the start and the end.
     * This includes the ASCII characters '\t', '\n', '\v', '\f', '\r', and ' '.
     */
    static std::string trimmed(const std::string &str);

    /**
     * Replaces n characters beginning at index position with the string after and returns a reference to this string.
     */
    static std::string replace(const std::string &str, const std::string &src, const std::string &dest);
};
}
}

#endif //STRING_UTIL_H
